//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.lyyzoo.util;

import com.google.common.collect.Lists;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.http.util.Asserts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class Reflections {
    private static final String SETTER_PREFIX = "set";
    private static final String GETTER_PREFIX = "get";
    private static final String CGLIB_CLASS_SEPARATOR = "$$";
    private static Logger logger = LoggerFactory.getLogger(Reflections.class);

    public Reflections() {
    }

    public static Object invokeGetter(Object obj, String propertyName) {
        Object object = obj;
        String[] var3 = StringUtils.split(propertyName, ".");
        int var4 = var3.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String name = var3[var5];
            String getterMethodName = "get" + StringUtils.capitalize(name);
            object = invokeMethod(object, getterMethodName, new Class[0], new Object[0]);
        }

        return object;
    }

    public static void invokeSetter(Object obj, String propertyName, Object value) {
        Object object = obj;
        String[] names = StringUtils.split(propertyName, ".");

        for(int i = 0; i < names.length; ++i) {
            String getterMethodName;
            if (i < names.length - 1) {
                getterMethodName = "get" + StringUtils.capitalize(names[i]);
                object = invokeMethod(object, getterMethodName, new Class[0], new Object[0]);
            } else {
                getterMethodName = "set" + StringUtils.capitalize(names[i]);
                invokeMethodByName(object, getterMethodName, new Object[]{value});
            }
        }

    }

    public static Object getFieldValue(Object obj, String fieldName) {
        Field field = getAccessibleField(obj, fieldName);
        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        } else {
            Object result = null;

            try {
                result = field.get(obj);
            } catch (IllegalAccessException var5) {
                logger.error("不可能抛出的异常{}", var5.getMessage());
            }

            return result;
        }
    }

    public static void setFieldValue(Object obj, String fieldName, Object value) {
        Field field = getAccessibleField(obj, fieldName);
        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        } else {
            try {
                field.set(obj, value);
            } catch (IllegalAccessException var5) {
                logger.error("不可能抛出的异常:{}", var5.getMessage());
            }

        }
    }

    public static Object invokeMethod(Object obj, String methodName, Class<?>[] parameterTypes, Object[] args) {
        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
        if (method == null) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
        } else {
            try {
                return method.invoke(obj, args);
            } catch (Exception var6) {
                throw convertReflectionExceptionToUnchecked(var6);
            }
        }
    }

    public static Object invokeMethodByName(Object obj, String methodName, Object[] args) {
        Method method = getAccessibleMethodByName(obj, methodName);
        if (method == null) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
        } else {
            try {
                return method.invoke(obj, args);
            } catch (Exception var5) {
                throw convertReflectionExceptionToUnchecked(var5);
            }
        }
    }

    public static Field getAccessibleField(Object obj, String fieldName) {
        Validate.notNull(obj, "object can't be null", new Object[0]);
        Validate.notBlank(fieldName, "fieldName can't be blank", new Object[0]);
        Class superClass = obj.getClass();

        while(superClass != Object.class) {
            try {
                Field field = superClass.getDeclaredField(fieldName);
                makeAccessible(field);
                return field;
            } catch (NoSuchFieldException var4) {
                superClass = superClass.getSuperclass();
            }
        }

        return null;
    }

    public static Method getAccessibleMethod(Object obj, String methodName, Class<?>... parameterTypes) {
        Validate.notNull(obj, "object can't be null", new Object[0]);
        Validate.notBlank(methodName, "methodName can't be blank", new Object[0]);
        Class searchType = obj.getClass();

        while(searchType != Object.class) {
            try {
                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
                makeAccessible(method);
                return method;
            } catch (NoSuchMethodException var5) {
                searchType = searchType.getSuperclass();
            }
        }

        return null;
    }

    public static Method getAccessibleMethodByName(Object obj, String methodName) {
        Validate.notNull(obj, "object can't be null", new Object[0]);
        Validate.notBlank(methodName, "methodName can't be blank", new Object[0]);

        for(Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
            Method[] methods = searchType.getDeclaredMethods();
            Method[] var4 = methods;
            int var5 = methods.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                Method method = var4[var6];
                if (method.getName().equals(methodName)) {
                    makeAccessible(method);
                    return method;
                }
            }
        }

        return null;
    }

    public static void makeAccessible(Method method) {
        if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {
            method.setAccessible(true);
        }

    }

    public static void makeAccessible(Field field) {
        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
            field.setAccessible(true);
        }

    }

    public static <T> Class<T> getClassGenricType(Class clazz) {
        return getClassGenricType(clazz, 0);
    }

    public static Class getClassGenricType(Class clazz, int index) {
        Type genType = clazz.getGenericSuperclass();
        if (!(genType instanceof ParameterizedType)) {
            logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
            return Object.class;
        } else {
            Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
            if (index < params.length && index >= 0) {
                if (!(params[index] instanceof Class)) {
                    logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
                    return Object.class;
                } else {
                    return (Class)params[index];
                }
            } else {
                logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
                return Object.class;
            }
        }
    }

    public static Class<?> getUserClass(Object instance) {
        Asserts.notNull(instance, "Instance must not be null");
        Class clazz = instance.getClass();
        if (clazz != null && clazz.getName().contains("$$")) {
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null && !Object.class.equals(superClass)) {
                return superClass;
            }
        }

        return clazz;
    }

    public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
        if (!(e instanceof IllegalAccessException) && !(e instanceof IllegalArgumentException) && !(e instanceof NoSuchMethodException)) {
            if (e instanceof InvocationTargetException) {
                return new RuntimeException(((InvocationTargetException)e).getTargetException());
            } else {
                return e instanceof RuntimeException ? (RuntimeException)e : new RuntimeException("Unexpected Checked Exception.", e);
            }
        } else {
            return new IllegalArgumentException(e);
        }
    }

    public static Field getField(Class<?> clazz, String fieldName, Reflections.Accessible accessible) {
        Validate.notNull(clazz, "class can't be null", new Object[0]);
        Validate.notBlank(fieldName, "fieldName can't be blank", new Object[0]);

        try {
            Field field = clazz.getDeclaredField(fieldName);
            if (accessible.equals(Reflections.Accessible.yes)) {
                makeAccessible(field);
            }

            return field;
        } catch (NoSuchFieldException var5) {
            Class<?> superClazz = clazz.getSuperclass();
            if (superClazz != Object.class) {
                return getField(superClazz, fieldName);
            } else {
                throw Exceptions.unchecked(var5);
            }
        }
    }

    public static Field getField(Object obj, String fieldName, Reflections.Accessible accessible) {
        Validate.notNull(obj, "object can't be null", new Object[0]);
        Validate.notBlank(fieldName, "fieldName can't be blank", new Object[0]);
        return getField(obj.getClass(), fieldName, accessible);
    }

    public static Field getField(Object obj, String fieldName) {
        return getField(obj.getClass(), fieldName, Reflections.Accessible.yes);
    }

    public static Field getField(Class<?> clazz, String fieldName) {
        return getField(clazz, fieldName, Reflections.Accessible.yes);
    }

    public static List<Field> getFields(Class<?> clazz) {
        Validate.notNull(clazz, "class can't be null", new Object[0]);
        List<Field> fields = Lists.newArrayList();
        Collections.addAll(fields, clazz.getDeclaredFields());
        Class<?> superClazz = clazz.getSuperclass();
        if (superClazz != Object.class) {
            fields.addAll(getFields(superClazz));
        }

        return fields;
    }

    public static List<Field> getFields(Object obj) {
        Validate.notNull(obj, "object can't be null", new Object[0]);
        return getFields(obj.getClass());
    }

    public static Method getCallingMethod() {
        return getCallingMethod(3);
    }

    public static Method getCallingMethodByLogger() {
        return getCallingMethod(4);
    }

    public static Method getCallingMethod(int i) {
        Thread t = Thread.currentThread();
        StackTraceElement[] stackTrace = t.getStackTrace();
        StackTraceElement ste = stackTrace[i];
        String methodName = ste.getMethodName();
        String className = ste.getClassName();

        try {
            Class kls = Class.forName(className);

            do {
                Method[] var7 = kls.getDeclaredMethods();
                int var8 = var7.length;

                for(int var9 = 0; var9 < var8; ++var9) {
                    Method candidate = var7[var9];
                    if (candidate.getName().equals(methodName)) {
                        return candidate;
                    }
                }

                kls = kls.getSuperclass();
            } while(kls != null);
        } catch (Exception var11) {
            Exceptions.unchecked(var11);
        }

        return null;
    }

    public static Method getAccessibleMethods(Object obj, String methodName, Class<?>... parameterTypes) {
        Validate.notNull(obj, "object can't be null", new Object[0]);
        Validate.notBlank(methodName, "methodName can't be blank", new Object[0]);
        Class searchType;
        if (obj instanceof Class) {
            searchType = (Class)obj;
        } else {
            searchType = obj.getClass();
        }

        while(searchType != Object.class) {
            try {
                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
                makeAccessible(method);
                return method;
            } catch (NoSuchMethodException var5) {
                var5.printStackTrace();
                searchType = searchType.getSuperclass();
            }
        }

        return null;
    }

    public static Class<?> getClass(Object instance) {
        Asserts.notNull(instance, "Instance must not be null");
        Class clazz = instance.getClass();
        if (clazz != null && clazz.getName().contains("$$")) {
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null && !Object.class.equals(superClass)) {
                return superClass;
            }
        }

        return clazz;
    }

    public static Class<?> getClass(Method method) {
        Asserts.notNull(method, "method must not be null");
        return method.getDeclaringClass();
    }

    public static String reflectionToString(Object obj) {
        return ToStringBuilder.reflectionToString(obj.getClass(), ToStringStyle.MULTI_LINE_STYLE);
    }

    public static String[] getMethodParamNames(Class<?> clazz, String methodName) throws Exception {
        Class<?>[] paramTypes = null;
        return getMethodParamNames(clazz, methodName, (Class[])paramTypes);
    }

    public static String[] getMethodParamNames(Class<?> clazz, String methodName, Class<?>... paramTypes) throws Exception {
        ClassPool classPool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(clazz);
        classPool.insertClassPath(classPath);
        CtClass ctClass = classPool.get(clazz.getName());
        CtMethod ctMethod = null;
        if (paramTypes == null) {
            ctMethod = ctClass.getDeclaredMethod(methodName);
        } else {
            ctMethod = ctClass.getDeclaredMethod(methodName, classPool.get(getParamTypesNames(paramTypes)));
        }

        return getMethodParamNames(ctMethod);
    }

    public static String[] getMethodParamNames(Method method) throws RuntimeException {
        ClassPool classPool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(method.getDeclaringClass());
        classPool.insertClassPath(classPath);

        try {
            CtClass ctClass = classPool.get(method.getDeclaringClass().getName());
            CtMethod ctMethod = ctClass.getDeclaredMethod(method.getName(), classPool.get(getParamTypesNames(method.getParameterTypes())));
            return getMethodParamNames(ctMethod);
        } catch (Exception var5) {
            throw new RuntimeException(var5);
        }
    }

    private static String[] getMethodParamNames(CtMethod ctMethod) throws RuntimeException {
        CtClass ctClass = ctMethod.getDeclaringClass();
        MethodInfo methodInfo = ctMethod.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute)codeAttribute.getAttribute("LocalVariableTable");
        if (attr == null) {
            throw new RuntimeException(ctClass.getName());
        } else {
            try {
                String[] paramNames = new String[ctMethod.getParameterTypes().length];
                int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;

                for(int i = 0; i < paramNames.length; ++i) {
                    paramNames[i] = attr.variableName(i + pos);
                }

                return paramNames;
            } catch (Exception var8) {
                throw new RuntimeException(var8);
            }
        }
    }

    public static String[] getParamTypesNames(Class<?>... paramTypes) {
        String[] paramTypeNames = new String[paramTypes.length];

        for(int i = 0; i < paramTypes.length; ++i) {
            paramTypeNames[i] = paramTypes[i].getName();
        }

        return paramTypeNames;
    }

    public static Class<?> getGenericMethodReturnTypes(Method method) {
        Type returnType = method.getGenericReturnType();
        if (returnType instanceof ParameterizedType) {
            ParameterizedType type = (ParameterizedType)returnType;
            Type[] typeArguments = type.getActualTypeArguments();
            int var5 = typeArguments.length;
            byte var6 = 0;
            if (var6 < var5) {
                Type typeArgument = typeArguments[var6];
                Class<?> typeArgClass = (Class)typeArgument;
                return typeArgClass;
            }
        }

        return null;
    }

    public static Class<?> getGenericMethodParameterTypes(Method method) {
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        Type[] var2 = genericParameterTypes;
        int var3 = genericParameterTypes.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Type genericParameterType = var2[var4];
            if (genericParameterType instanceof ParameterizedType) {
                ParameterizedType aType = (ParameterizedType)genericParameterType;
                Type[] parameterArgTypes = aType.getActualTypeArguments();
                int var9 = parameterArgTypes.length;
                byte var10 = 0;
                if (var10 < var9) {
                    Type parameterArgType = parameterArgTypes[var10];
                    Class<?> parameterArgClass = (Class)parameterArgType;
                    return parameterArgClass;
                }
            }
        }

        return null;
    }

    public static Class<?> getGenericFieldTypes(Field field) {
        Type genericFieldType = field.getGenericType();
        if (genericFieldType instanceof ParameterizedType) {
            ParameterizedType aType = (ParameterizedType)genericFieldType;
            Type[] fieldArgTypes = aType.getActualTypeArguments();
            int var5 = fieldArgTypes.length;
            byte var6 = 0;
            if (var6 < var5) {
                Type fieldArgType = fieldArgTypes[var6];
                Class<?> fieldArgClass = (Class)fieldArgType;
                return fieldArgClass;
            }
        }

        return null;
    }

    public static enum Accessible {
        yes,
        no;

        private Accessible() {
        }
    }
}
